
`include "defines.v"

module ctr_mem(
    input  wire              rst,

    // cpu接口
    input  wire [`BUS_WIDTH] mem_ren,
    input  wire              mem_wen,
    input  wire [`BUS_WIDTH] addr,
    input  wire [`BUS_WIDTH] data_in,
    input  wire [2 :      0] width_sel,
    output reg  [`BUS_WIDTH] data_out,

    // mem接口
    input  wire [`BUS_WIDTH] mem_rdata,
    output reg  [`BUS_WIDTH] mem_wdata,
    output reg  [`BUS_WIDTH] mem_wmask
);  

    
    always @(*) begin
        if      (rst) begin
            data_out  = `ZERO_WORD;
            mem_wdata = `ZERO_WORD;
            mem_wmask = `ZERO_WORD;
        end
        else if (mem_ren) begin    // Loads
            mem_wdata = `ZERO_WORD;    // 可取任意值
            mem_wmask = `ZERO_WORD;    // 可取任意值
            case (width_sel[1 : 0])
                2'b00: begin    // lb, lbu
                    case (addr[2 : 0])
                        3'b000: begin
                            data_out = {56'b0, mem_rdata[7  :  0]};
                        end
                        3'b001: begin
                            data_out = {56'b0, mem_rdata[15 :  8]};
                        end
                        3'b010: begin
                            data_out = {56'b0, mem_rdata[23 : 16]};
                        end
                        3'b011: begin
                            data_out = {56'b0, mem_rdata[31 : 24]};
                        end
                        3'b100: begin
                            data_out = {56'b0, mem_rdata[39 : 32]};
                        end
                        3'b101: begin
                            data_out = {56'b0, mem_rdata[47 : 40]};
                        end
                        3'b110: begin
                            data_out = {56'b0, mem_rdata[55 : 48]};
                        end
                        3'b111: begin
                            data_out = {56'b0, mem_rdata[63 : 56]};
                        end
                    endcase
                end
                2'b01: begin    // lh, lhu
                    case (addr[2 : 1])
                        2'b00: begin
                            data_out = {48'b0, mem_rdata[15 :  0]};
                        end
                        2'b01: begin
                            data_out = {48'b0, mem_rdata[31 : 16]};
                        end
                        2'b10: begin
                            data_out = {48'b0, mem_rdata[47 : 32]};
                        end
                        2'b11: begin
                            data_out = {48'b0, mem_rdata[63 : 48]};
                        end
                    endcase
                end
                2'b10: begin    // lw, lwu
                    case (addr[2])
                        1'b0: begin
                            data_out = {32'b0, mem_rdata[31 :  0]};
                        end 
                        1'b1: begin
                            data_out = {32'b0, mem_rdata[63 : 32]};
                        end
                    endcase
                end
                2'b11: begin    // ld
                    data_out = mem_rdata;
                end 
            endcase            
        end
        else if (mem_wen) begin    // Stores
            data_out = `ZERO_WORD;
            case (width_sel[1 : 0])
                2'b00: begin    // sb
                    case (addr[2 : 0])
                        3'b000: begin
                            mem_wdata = data_in;
                            mem_wmask = 64'h00000000_000000ff;
                        end
                        3'b001: begin
                            mem_wdata = (data_in << 64'h8);
                            mem_wmask = 64'h00000000_0000ff00;
                        end
                        3'b010: begin
                            mem_wdata = (data_in << 64'h10);
                            mem_wmask = 64'h00000000_00ff0000;
                        end
                        3'b011: begin
                            mem_wdata = (data_in << 64'h18);
                            mem_wmask = 64'h00000000_ff000000;
                        end
                        3'b100: begin
                            mem_wdata = (data_in << 64'h20);
                            mem_wmask = 64'h000000ff_00000000;
                        end
                        3'b101: begin
                            mem_wdata = (data_in << 64'h28);
                            mem_wmask = 64'h0000ff00_00000000;
                        end
                        3'b110: begin
                            mem_wdata = (data_in << 64'h30);
                            mem_wmask = 64'h00ff0000_00000000;
                        end
                        3'b111: begin
                            mem_wdata = (data_in << 64'h38);
                            mem_wmask = 64'hff000000_00000000;
                        end
                    endcase
                end
                2'b01: begin    // sh
                    case (addr[2 : 1])
                        2'b00: begin
                            mem_wdata = data_in;
                            mem_wmask = 64'h00000000_0000ffff;
                        end
                        2'b01: begin
                            mem_wdata = (data_in << 64'h10);
                            mem_wmask = 64'h00000000_ffff0000;
                        end
                        2'b10: begin
                            mem_wdata = (data_in << 64'h20);
                            mem_wmask = 64'h0000ffff_00000000;
                        end
                        2'b11: begin
                            mem_wdata = (data_in << 64'h30);
                            mem_wmask = 64'hffff0000_00000000;
                        end
                    endcase
                end
                2'b10: begin    // sw
                    case (addr[2])
                        1'b0: begin
                            mem_wdata = data_in;
                            mem_wmask = 64'h00000000_ffffffff;
                        end 
                        1'b1: begin
                            mem_wdata = (data_in << 64'h20);
                            mem_wmask = 64'hffffffff_00000000;
                        end
                    endcase
                end
                2'b11: begin    // sd
                    mem_wdata = data_in;
                    mem_wmask = 64'hffffffff_ffffffff;
                end 
            endcase
        end
        else begin
            data_out  = `ZERO_WORD;
            mem_wdata = `ZERO_WORD;    // 可取任意值
            mem_wmask = `ZERO_WORD;    // 可取任意值
        end
    end
    

endmodule
